package org.jmh.gift.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import org.jmh.gift.enums.SystemErrorCode;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import org.jmh.gift.constrans.ShopCarConstatns;
import org.jmh.gift.client.GiftClient;
import org.jmh.gift.domain.GoodsSku;
import org.jmh.gift.domain.ShopCar;
import org.jmh.gift.dto.AddDTO;
import org.jmh.gift.dto.DeleteDTO;
import org.jmh.gift.dto.UpdateCountDTO;
import org.jmh.gift.dto.UpdateSelDTO;
import org.jmh.gift.exception.BusinessException;
import org.jmh.gift.mapper.ShopCarMapper;
import org.jmh.gift.service.IShopCarService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.jmh.gift.strategy.IShopCarStrategy;
import org.jmh.gift.strategy.ShopCarStrategyFactory;
import org.jmh.gift.util.AjaxResult;
import org.jmh.gift.util.JMHAssert;
import org.jmh.gift.util.TenantBase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lingfeng
 * @since 2024-08-01
 */
@Service
public class ShopCarServiceImpl extends ServiceImpl<ShopCarMapper, ShopCar> implements IShopCarService {

    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private GiftClient giftClient;

    private String groupStrategy;

/*更改状态*/
    @Override
    public void updateSel(UpdateSelDTO dto) {
        //根据请求userid查询redis数据
        BoundHashOperations<String, String, String> hashOps = redisTemplate
                .boundHashOps(ShopCarConstatns.SHOP_CAR_PREFIX + dto.getUserId());

        //根据skuId查询购物车信息
        String s = hashOps.get(dto.getSkuId().toString());
        ShopCar shopCar = JSONObject.parseObject(s, ShopCar.class);

        //修改选择状态（和修改数量一模一样，除了修改的数据不一样其他的没有一点差别）
            shopCar.setSelect(dto.getIsSelect());
            shopCar.setUpdateTime(new Date());
        // 4 重新放入redis
        assert shopCar != null;
        hashOps.put(shopCar.getSkuId().toString(),JSONObject.toJSONString(shopCar));

        //设置redis过期时间
        hashOps.expire(30,TimeUnit.HOURS);
    }

/*查询（加商铺品牌）*/
    @Override
    public Map<TenantBase, List<ShopCar>> getByUserId(Long userId) {
        // 1 根据userId查询redis里满足条件的数据
        BoundHashOperations<String, String, String> hashOps = redisTemplate
                .boundHashOps(ShopCarConstatns.SHOP_CAR_PREFIX + userId);
        // 获取第一个key的所有value值，将redis里未被删除的数据返给前端
        List<String> values = hashOps.values();
        Map<TenantBase, List<ShopCar>> maps = null;
        if(CollectionUtil.isNotEmpty(values)){
            //将字符串集合转换为shopcar集合
            List<ShopCar> shopCars = values.stream()
                    .map(x -> JSONObject.parseObject(x, ShopCar.class)).collect(Collectors.toList());
            //过滤redis里面未被删除的数据
            shopCars = shopCars.stream().filter(x -> x.getDeleted() == 0).collect(Collectors.toList());
            //分组后返回给前端
            if(CollectionUtil.isNotEmpty(shopCars)){
                maps = shopCars.stream().collect(Collectors.groupingBy(x ->
                        new TenantBase(x.getTenantId(),x.getTenantName())));
            }
        }else{
            //判断redis里是否有数据若没有则通过userid去数据库查找购物车数据
            List<ShopCar> shopCars = selectList(new EntityWrapper<ShopCar>().eq("user_id", userId));
            //将数据库查到的数据放入redis再返值
            if(CollectionUtil.isNotEmpty(shopCars)){
                for (ShopCar shopCar : shopCars) {
                    hashOps.put(shopCar.getSkuId().toString(),JSONObject.toJSONString(shopCar));
                }
                maps = shopCars.stream().collect(Collectors.groupingBy(x ->
                        new TenantBase(x.getTenantId(),x.getTenantName())));
            }
        }
        //设置redis过期时间
        hashOps.expire(27,TimeUnit.HOURS);
        return maps;
    }

/*购物车新增*/
    @Override
    public void add(AddDTO dto) {
        //根据userId在redis里查数据
        BoundHashOperations<String, String, String> hashOps = redisTemplate
                .boundHashOps(ShopCarConstatns.SHOP_CAR_PREFIX + dto.getUserId());
        List<String> values = hashOps.values();
        List<ShopCar> shopCars= super.selectList(new EntityWrapper<ShopCar>().eq("user_id", dto.getUserId()));
        //redis没有去数据库查，然后放入redis
        if(Objects.isNull(values)){
            for (ShopCar shopCar : shopCars) {
                hashOps.put(shopCar.getSkuId().toString(), JSONObject.toJSONString(shopCar));
            }
        }
        //获取用户在redis里存放的数据
        values = hashOps.values();
        ShopCar shopCar;
        //查询redis/数据库里是否存在数据
        if(CollectionUtil.isNotEmpty(values))
        {
            List<ShopCar> carList = values.stream().map(x -> JSONObject.parseObject(x, ShopCar.class)).collect(Collectors.toList());
            shopCar = carList.stream().filter(x -> x.getSkuId().equals(dto.getSkuId())).findFirst().orElse(null);
            //修改数量数据放入redis
            if(Objects.nonNull(shopCar)){
                if(shopCar.getDeleted() == 1){
                    shopCar.setDeleted(0);
                    shopCar.setNum(dto.getNum());
                }else{
                    shopCar.setNum(shopCar.getNum()+dto.getNum());
                }
            }else{
                // 若物品不存在，则远程调用去数据库拿去数据存入redis
                shopCar = commonShopCar(dto);
            }
        }else{
            //直接通过skuId获取礼物信息,构建购物车对象,存入redis
            shopCar = commonShopCar(dto);
        }
        hashOps.put(shopCar.getSkuId().toString(),JSONObject.toJSONString(shopCar));
        //设置redis过期时间
        hashOps.expire(30, TimeUnit.HOURS);
    }

/*删除商品*/
    @Override
    public void deleteBySkuId(DeleteDTO dto) {
        //根据请求userid查询redis数据
        BoundHashOperations<String, String, String> hashOps = redisTemplate
                .boundHashOps(ShopCarConstatns.SHOP_CAR_PREFIX + dto.getUserId());
        //根据skuId查询购物车信息
        String s = hashOps.get(dto.getSkuId().toString());
        ShopCar shopCar = JSONObject.parseObject(s, ShopCar.class);
        //修改商品数量
        if (shopCar != null) {
            shopCar.setDeleted(1);
        }
        if (shopCar != null) {
            shopCar.setUpdateTime(new Date());
        }

        // 4 重新放入redis
        hashOps.put(shopCar.getSkuId().toString(),JSONObject.toJSONString(shopCar));
        //设置redis过期时间
        hashOps.expire(30,TimeUnit.HOURS);
    }

/*更改数量*/
    @Override
    public void updateCount(UpdateCountDTO dto) {
        //根据请求userid查询redis数据
        BoundHashOperations<String, String, String> hashOps = redisTemplate
                .boundHashOps(ShopCarConstatns.SHOP_CAR_PREFIX + dto.getUserId());
        //根据skuId查询购物车信息
        String s = hashOps.get(dto.getSkuId().toString());
        ShopCar shopCar = JSONObject.parseObject(s, ShopCar.class);

        //修改商品数量
        if (shopCar != null) {
            shopCar.setNum(dto.getNum());
        }
        if (shopCar != null) {
            shopCar.setUpdateTime(new Date());
        }
        //重新放入redis
        hashOps.put(shopCar.getSkuId().toString(),JSONObject.toJSONString(shopCar));
        //设置redis过期时间
        hashOps.expire(30,TimeUnit.HOURS);
    }

    /*公共封装购物车的shopcar对象*/

    private ShopCar commonShopCar(AddDTO dto) {
        AjaxResult ajaxResult = giftClient.get(dto.getSkuId());
        if(!ajaxResult.getSuccess()){
            throw new BusinessException("添加购物车失败!");
        }
        //封装shopCar
        String s = JSONObject.toJSONString(ajaxResult.getData());
        GoodsSku goodsSku = JSONObject.parseObject(s, GoodsSku.class);
        ShopCar car = new ShopCar();
        car.setSpuId(goodsSku.getSpuId());
        car.setSpuName(goodsSku.getSpuName());
        car.setSkuId(goodsSku.getId());
        car.setSkuInfo(goodsSku.getSkuName());
        car.setAddPrice(goodsSku.getPrice());
        car.setPrice(goodsSku.getPrice());
        car.setUserId(dto.getUserId());
        car.setUsername(dto.getUsername());
        car.setTenantId(goodsSku.getTenantId());
        car.setTenantName(goodsSku.getTenantId()+"");
        car.setSelect(true);
        car.setCreateTime(new Date());
        car.setNum(dto.getNum());
        return car;
    }
    @Override
    public void jobTest() {
        //获取redis里的键
        Set<String> keys = redisTemplate.keys("shop_car_*");
        // 使用设计模式:策略模式+工厂模式+反射
        IShopCarStrategy strategy = ShopCarStrategyFactory.createStrategy(this.groupStrategy);
        Map<String, List<String>> listMap = strategy.group(keys);
        Iterator<Map.Entry<String, List<String>>> iterator = listMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, List<String>> entry = iterator.next();
            List<String> keyList = entry.getValue();
            List<Long> delIdsAll = new ArrayList<>();
            List<ShopCar> addOrUpdateAll = new ArrayList<>();
            for (String key : keyList) {
                BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(key);
                //每个用户的所有购物车数据
                List<String> shopCarStrs = hashOps.values();
        //将字符串转为ShopCar对象
                List<ShopCar> shopCars = shopCarStrs.stream()
                        .map(x -> JSONObject.parseObject(x, ShopCar.class)).collect(Collectors.toList());
                List<Long> delIds = shopCars.stream().filter(x -> x.getDeleted() == 1)
                        .map(ShopCar::getId).collect(Collectors.toList());
                delIdsAll.addAll(delIds);
                List<ShopCar> addOrUpdateList = shopCars.stream().filter(x -> x.getDeleted() == 0).collect(Collectors.toList());
                addOrUpdateAll.addAll(addOrUpdateList);
                if(CollectionUtil.isNotEmpty(delIdsAll)){
                    super.deleteBatchIds(delIdsAll);
                }
        //对一个分组内的用户数据统一处理完了以后,在外面统一操作数据库
                if(CollectionUtil.isNotEmpty(addOrUpdateAll)){
                    super.insertOrUpdateBatch(addOrUpdateAll);
                }
            }
    }
}

    @Override
    public void deleteShopCarBySkuId(DeleteDTO deleteDTO) {
        BoundHashOperations<String, String, String> hashOps = redisTemplate
                .boundHashOps(ShopCarConstatns.SHOP_CAR_PREFIX + deleteDTO.getUserId());
        String s = hashOps.get(deleteDTO.getSkuId().toString());
        JMHAssert.isNotBlank(s,SystemErrorCode.RESPONSE_CODE_400600);
        ShopCar shopCar = JSONObject.parseObject(s, ShopCar.class);
        if (shopCar != null) {
            shopCar.setDeleted(1);
        }
        if (shopCar != null) {
            shopCar.setUpdateTime(new Date());
        }
        if (shopCar != null) {
            hashOps.put(shopCar.getSkuId().toString(),JSONObject.toJSONString(shopCar));
        }
        hashOps.expire(27,TimeUnit.HOURS);
    }
}
